「在函式裡,我們計算程式行數,來衡量函式的大小;在類別裡,我們使用不同的量測方式,我們計算職責的數量」
取自: Clean Code (p.152)

public class EmployeeUtils {  
    // 取資料
    public void FetchEmployeeDetails(string employeeId) 
    // 存資料
    public void SaveEmployeeDetails(EmployeeModel employeeDetails)
    // 驗證資料
    public void ValidateEmployeeDetails(EmployeeModel employeeDetails)
    // 輸出資料
    public void ExportEmpDetailsToCSV(EmployeeModel employeDetails)
    // 引入資料
    public void ImportEmpDetailsForDb(EmployeeModel employeeDetails) 
    // 員工資料細節
    private class EmployeeModel {  
        public string EmployeeId;
        public string EmployeeName;
        public string EmpplyeeAddress;
        public string EmployeeDesignation;
        public double EmployeeSalary;
    }  
}  
注意: 不要把它跟「函式只做一件事」搞混!
P.S. 關於 SOLID 設計原則在之後介紹 Clean Architecture 時,筆者會再次介紹
public class Stack 
{
  private int topOfStack = 0;
  List<Integer> elements = new LinkedList<Integer>();
  public int size() {
    return topOfStack;
  }
  public void push(int element) {
    topOfStack++;
    elements.add(element);
  }
  public int pop() throws PoppedWhenEmpty {
    if (topOfStack == 0)
      throw new PoppedWhenEmpty();
    int element = elements.get(--topOfStack);
    elements.remove(topOfStack);
    return element;
  }
}
上例中只有 Size() 沒有同時使用到類別的 2 個變數,這是一個非常有凝聚力的類別
違反 SRP 的 SQL 類別
public class Sql {
  public Sql(String table, Column[] columns)
  public String create()
  public String insert(Object[] fields)
  public String selectAll()
  public String findByKey(String keyColumn, String keyValue)
  public String select(Column column, String pattern)
  public String select(Criteria criteria)
  public String preparedInsert()
  private String columnList(Column[] columns)
  private String valuesList(Object[] fields, final Column[] columns)
  private String selectWithCriteria(String criteria)
  private String placeholderList(Column[] columns)
}
以上例來說,當我們想要新增指令 (e.g., Delete)、或者修改某指令的細節,都需要更動到此類別。很明顯地這個類別有超過 1 個以上的修改理由
那麼,何時該做職責拆解?
想讓系統的每一個類別都符合 SRP 原則並不是一件輕鬆的事,且可能會流於過度設計 (Over-Design)。所以關鍵在於,未來更動或新增 SQL 類別的機會多不多? 若未來須新增 Update 功能,就是一個修補設計的好機會
重構後的 SQL 符合「單一職責原則 (SRP)」 和 「開放封閉原則 (OCP)」
abstract public class Sql {
   public Sql(String table, Column[] columns)
   abstract public String generate();
}
public class CreateSql extends Sql {
   public CreateSql(String table, Column[] columns)
   @Override public String generate()
}
public class SelectSql extends Sql {
   public SelectSql(String table, Column[] columns)
   @Override public String generate()
}
public class InsertSql extends Sql {
   public InsertSql(String table, Column[] columns, Object[] fields)
   @Override public String generate()
   private String valuesList(Object[] fields, final Column[] columns)
}
public class SelectWithCriteriaSql extends Sql {
   public SelectWithCriteriaSql(
   String table, Column[] columns, Criteria criteria)
   @Override public String generate()
}
public class SelectWithMatchSql extends Sql {
   public SelectWithMatchSql(
   String table, Column[] columns, Column column, String pattern)
   @Override public String generate()
}
public class FindByKeySql extends Sql
   public FindByKeySql(
   String table, Column[] columns, String keyColumn, String keyValue)
   @Override public String generate()
}
public class PreparedInsertSql extends Sql {
   public PreparedInsertSql(String table, Column[] columns)
   @Override public String generate() {
   private String placeholderList(Column[] columns)
}
public class Where {
   public Where(String criteria)
   public String generate()
}
public class ColumnList {
   public ColumnList(Column[] columns)
   public String generate()
}
重構後雖然多了許多程式碼,但我們可以發現每一個小功能的可讀性都大大地上昇了,且函式之間幾乎沒有任何耦合,這也使得測試程式變得更容易撰寫。而當我們想新增指令時,只要新增一個子類別即可,沒有任何既有的程式碼會被更動
「整潔的程式碼幫助我們在較低抽象層次上,達成這個目標。在本章中,讓我們來思考該如何在較高的抽象層次,達成整潔的目標」
取自: Clean Code (p.170)
public Service getService() {
   if (service == null)
     service = new MyServiceImpl(...);
   return service;
}


Kent Beck's 簡單設計四守則 (Four Rules of Software Design)
遵守以下四個守則就能更容易使軟體善用「單一職責原則 (SRP)」及「相依性反向原則 (DIP)」
- 執行完所有的測試 => Passes the tests
- 表達程式設計師的本意 => Reveals intention (should be easy to understand)
- 沒有重複的部分 => No duplication (DRY)
- 最小化類別和方法的數量 => Fewest elements
取自: Clean Code (p.190)
註: 筆者發現中文書的翻譯與順序和原文有些許出入,附上原文:
